﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Assist;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Revit;
using YArchitech.Revit.Electric.Common;
using YArchitech.Revit.RevitExtension;
using HYView;

namespace HYRElectric.WirePlace
{
	[Regeneration(RegenerationOption.Manual)]
	[Transaction(TransactionMode.Manual)]
	public class CmdCableChannel : IExternalCommand
	{
		public Result Execute(ExternalCommandData cmdData, ref string message, ElementSet elements)
		{
			UIApplication application = cmdData.Application;
			this.app = application.Application;
			this.doc = application.ActiveUIDocument.Document;
			this.sel = application.ActiveUIDocument.Selection;
			this.v = this.doc.ActiveView;
			this.level = this.v.GenLevel;
			if (!(this.v is ViewPlan))
			{
				Result result = SwitchView.SetUsableView(HYView.CmdViewType.FloorPlan, cmdData);
				if (result != Result.Succeeded)
				{
					return result;
				}
			}
			Transaction transaction = new Transaction(this.doc, "CableChannel");
			try
			{
				using (DlgCableChannel dlgCableChannel = new DlgCableChannel())
				{
					DialogResult dialogResult = dlgCableChannel.ShowDialog();
					if (dialogResult == DialogResult.Cancel)
					{
						return Autodesk.Revit.UI.Result.Cancelled;
					}
					if (dialogResult == DialogResult.OK)
					{
						transaction.Start();
						this.channelDeep = Convert.ToDouble(dlgCableChannel.txtChannelDeep.Text.Trim());
						this.channelWidth = Convert.ToDouble(dlgCableChannel.txtChannelWidth.Text.Trim());
						IList<Reference> list = this.sel.PickObjects(Autodesk.Revit.UI.Selection.ObjectType.Element, new CableChannelFilter(), "请选择要替换的导线、模型线、桥架");
						this.SetCableTrayPara();
						if (list.Count <= 0)
						{
							MessageBox.Show("没有选择的对象！", "盈建科提示");
							transaction.RollBack();
							return Autodesk.Revit.UI.Result.Cancelled;
						}
						List<Curve> list2 = new List<Curve>();
						List<Curve> list3 = new List<Curve>();
						foreach (Reference reference in list)
						{
							LocationCurve locationCurve = this.doc.GetElement(reference).Location as LocationCurve;
							list2.Add(locationCurve.Curve);
							list3.Add(locationCurve.Curve);
						}
						List<XYZ> list4 = new List<XYZ>();
						foreach (Curve curve in list2)
						{
							foreach (Curve curve2 in list3)
							{
								XYZ xyz = this.IntersectionPoint(curve, curve2);
								if (xyz != null && !this.RemoveDuplicates(list4, xyz))
								{
									list4.Add(xyz);
								}
							}
						}
						List<CableTray> list5 = new List<CableTray>();
						foreach (Curve curve3 in list2)
						{
							List<XYZ> list6 = new List<XYZ>();
							foreach (XYZ xyz2 in list4)
							{
								if (curve3.Distance(xyz2) < this.js)
								{
									list6.Add(xyz2);
								}
							}
							if (list6.Count > 0)
							{
								List<Line> list7 = new List<Line>();
								foreach (XYZ endPoint in list6)
								{
									try
									{
										if (list6.Count == 1)
										{
											try
											{
												list7.Add(YJKLineEx.YJKGetBound(curve3.GetEndPoint(0), endPoint));
												continue;
											}
											catch (Exception)
											{
												list7.Add(YJKLineEx.YJKGetBound(curve3.GetEndPoint(1), endPoint));
												continue;
											}
										}
										list7.Add(YJKLineEx.YJKGetBound(curve3.GetEndPoint(0), endPoint));
									}
									catch (Exception)
									{
									}
								}
								if (list7.Count > 0)
								{
									for (int i = 0; i < list7.Count - 1; i++)
									{
										for (int j = 0; j < list7.Count - 1 - i; j++)
										{
											if (list7[j].Length > list7[j + 1].Length)
											{
												Line value = list7[j];
												list7[j] = list7[j + 1];
												list7[j + 1] = value;
											}
										}
									}
									List<XYZ> list8 = new List<XYZ>();
									foreach (Line curve4 in list7)
									{
										list8.Add(curve4.GetEndPoint(1));
									}
									CableTray cableTray = this.CreateCableTray(curve3.GetEndPoint(0), list8[0]);
									if (cableTray != null)
									{
										list5.Add(cableTray);
									}
									CableTray cableTray2 = this.CreateCableTray(list8[list8.Count - 1], curve3.GetEndPoint(1));
									if (cableTray2 != null)
									{
										list5.Add(cableTray2);
									}
									for (int k = 0; k < list8.Count - 1; k++)
									{
										int num = k;
										CableTray cableTray3 = this.CreateCableTray(list8[num], list8[num + 1]);
										if (cableTray3 != null)
										{
											list5.Add(cableTray3);
										}
									}
								}
							}
							else
							{
								this.CreateCableTray(curve3.GetEndPoint(0), curve3.GetEndPoint(1));
							}
						}
						foreach (XYZ xyz3 in list4)
						{
							List<CableTray> list9 = new List<CableTray>();
							foreach (CableTray cableTray4 in list5)
							{
								if ((cableTray4.Location as LocationCurve).Curve.Distance(new XYZ(xyz3.X, xyz3.Y, AssistFunc.mmToFeet(-this.channelWidth))) < this.js)
								{
									list9.Add(cableTray4);
								}
							}
							switch (list9.Count)
							{
							case 2:
								this.CreateElbow(list9);
								break;
							case 3:
								this.CreateTeeFitting(list9, new XYZ(xyz3.X, xyz3.Y, AssistFunc.mmToFeet(-this.channelWidth)));
								break;
							case 4:
								this.CreateNewCrossFitting(list9, new XYZ(xyz3.X, xyz3.Y, AssistFunc.mmToFeet(-this.channelWidth)));
								break;
							}
						}
						foreach (Reference reference2 in list)
						{
							Element element = this.doc.GetElement(reference2);
							this.doc.DeleteElement(element);
						}
						this.doc.Regenerate();
						transaction.Commit();
					}
				}
			}
			catch (Exception)
			{
				transaction.RollBack();
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private void SetCableTrayPara()
		{
			this.v.get_Parameter(BuiltInParameter.VIEW_DETAIL_LEVEL).Set(3);
			Categories categories = this.doc.Settings.Categories;
			Category category = categories.get_Item(BuiltInCategory.OST_CableTray);
			Category category2 = categories.get_Item(BuiltInCategory.OST_CableTrayFitting);
			this.doc.ActiveView.SetYJKVisibility(category, true);
			this.doc.ActiveView.SetYJKVisibility(category2, true);
		}

		private void CreateElbow(List<CableTray> allCableTrayByCurrentPoint)
		{
			try
			{
				IList<XYZ> list = new List<XYZ>();
				IList<Connector> list2 = new List<Connector>();
				ConnectorSetIterator connectorSetIterator = allCableTrayByCurrentPoint[0].ConnectorManager.Connectors.ForwardIterator();
				while (connectorSetIterator.MoveNext())
				{
					object obj = connectorSetIterator.Current;
					Connector connector = obj as Connector;
					list.Add(connector.Origin);
					list2.Add(connector);
				}
				IList<XYZ> list3 = new List<XYZ>();
				IList<Connector> list4 = new List<Connector>();
				ConnectorSetIterator connectorSetIterator2 = allCableTrayByCurrentPoint[1].ConnectorManager.Connectors.ForwardIterator();
				while (connectorSetIterator2.MoveNext())
				{
					object obj2 = connectorSetIterator2.Current;
					Connector connector2 = obj2 as Connector;
					list3.Add(connector2.Origin);
					list4.Add(connector2);
				}
				Line line = YJKLineEx.YJKGetBound(list.ElementAt(0), list.ElementAt(1));
				Curve curve = YJKLineEx.YJKGetBound(list3.ElementAt(0), list3.ElementAt(1));
				line.MakeUnbound();
				curve.MakeUnbound();
				IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
				SetComparisonResult setComparisonResult = line.Intersect(curve, out intersectionResultArray);
				XYZ xyz = null;
                if ((SetComparisonResult)(SetComparisonResult)4 != setComparisonResult && !intersectionResultArray.IsEmpty)
				{
					xyz = intersectionResultArray.get_Item(0).XYZPoint;
				}
				Connector connector3 = list2.ElementAt(0);
				if (xyz.DistanceTo(list.ElementAt(0)) > xyz.DistanceTo(list.ElementAt(1)))
				{
					connector3 = list2.ElementAt(1);
				}
				Connector connector4 = list4.ElementAt(0);
				if (xyz.DistanceTo(list3.ElementAt(0)) > xyz.DistanceTo(list3.ElementAt(1)))
				{
					connector4 = list4.ElementAt(1);
				}
				if (connector3 != null && connector4 != null)
				{
					connector3.ConnectTo(connector4);
					this.doc.Create.NewElbowFitting(connector3, connector4);
				}
			}
			catch (Exception)
			{
			}
		}

		private void CreateTeeFitting(List<CableTray> allCableTrayByCurrentPoint, XYZ point)
		{
			try
			{
				Curve curve = (allCableTrayByCurrentPoint[0].Location as LocationCurve).Curve;
				Curve curve2 = (allCableTrayByCurrentPoint[1].Location as LocationCurve).Curve;
				Curve curve3 = (allCableTrayByCurrentPoint[2].Location as LocationCurve).Curve;
				int num;
				if (this.IntersectionPoint(curve, curve2) == null)
				{
					num = 2;
				}
				else if (this.IntersectionPoint(curve, curve3) == null)
				{
					num = 1;
				}
				else
				{
					num = 0;
				}
				Connector connector = this.GetConnector(allCableTrayByCurrentPoint[0], point);
				Connector connector2 = this.GetConnector(allCableTrayByCurrentPoint[1], point);
				Connector connector3 = this.GetConnector(allCableTrayByCurrentPoint[2], point);
				if (connector != null && connector2 != null && connector3 != null)
				{
					switch (num)
					{
					case 0:
						this.doc.Create.NewTeeFitting(connector2, connector3, connector);
						break;
					case 1:
						this.doc.Create.NewTeeFitting(connector, connector3, connector2);
						break;
					case 2:
						this.doc.Create.NewTeeFitting(connector, connector2, connector3);
						break;
					}
				}
			}
			catch (Exception)
			{
			}
		}

		private void CreateNewCrossFitting(List<CableTray> allCableTrayByCurrentPoint, XYZ point)
		{
			try
			{
				int[] array = new int[2];
				Curve curve = (allCableTrayByCurrentPoint[0].Location as LocationCurve).Curve;
				Curve curve2 = (allCableTrayByCurrentPoint[1].Location as LocationCurve).Curve;
				Curve curve3 = (allCableTrayByCurrentPoint[2].Location as LocationCurve).Curve;
				Curve curve4 = (allCableTrayByCurrentPoint[3].Location as LocationCurve).Curve;
				if (this.IntersectionPoint(curve, curve2) == null)
				{
					array[0] = 2;
					array[1] = 3;
				}
				else if (this.IntersectionPoint(curve, curve3) == null)
				{
					array[0] = 1;
					array[1] = 3;
				}
				else if (this.IntersectionPoint(curve, curve4) == null)
				{
					array[0] = 1;
					array[1] = 2;
				}
				Connector connector = this.GetConnector(allCableTrayByCurrentPoint[0], point);
				Connector connector2 = this.GetConnector(allCableTrayByCurrentPoint[1], point);
				Connector connector3 = this.GetConnector(allCableTrayByCurrentPoint[2], point);
				Connector connector4 = this.GetConnector(allCableTrayByCurrentPoint[3], point);
				if (connector != null && connector2 != null && connector3 != null && connector4 != null)
				{
					if (array[0] == 2 && array[1] == 3)
					{
						this.doc.Create.NewCrossFitting(connector3, connector4, connector, connector2);
					}
					else if (array[0] == 1 && array[1] == 3)
					{
						this.doc.Create.NewCrossFitting(connector2, connector4, connector, connector3);
					}
					else if (array[0] == 1 && array[1] == 2)
					{
						this.doc.Create.NewCrossFitting(connector2, connector3, connector, connector4);
					}
				}
			}
			catch (Exception)
			{
			}
		}

		private Connector GetConnector(CableTray allCableTrayByCurrentPoint, XYZ point)
		{
			IList<Connector> list = new List<Connector>();
			ConnectorSetIterator connectorSetIterator = allCableTrayByCurrentPoint.ConnectorManager.Connectors.ForwardIterator();
			while (connectorSetIterator.MoveNext())
			{
				object obj = connectorSetIterator.Current;
				Connector item = obj as Connector;
				list.Add(item);
			}
			Connector result;
			if (list[0].Origin.IsAlmostEqualTo(point))
			{
				result = list[0];
			}
			else
			{
				result = list[1];
			}
			return result;
		}

		private CableTray CreateCableTray(XYZ start, XYZ end)
		{
			CableTray result;
			try
			{
				CableTrayType cableTrayType = this.GetCableTrayType();
				CableTray cableTray = CableTray.Create(this.doc, cableTrayType.Id, start, end, this.level.Id);
				this.GetSharedParameter(cableTray);
				cableTray.GetParameter("类别").Set("电缆沟");
				cableTray.GetParameter(BuiltInParameter.RBS_CABLETRAY_WIDTH_PARAM).Set(AssistFunc.mmToFeet(this.channelWidth));
				cableTray.GetParameter(BuiltInParameter.RBS_CABLETRAY_HEIGHT_PARAM).Set(AssistFunc.mmToFeet(this.channelDeep));
				cableTray.GetParameter(BuiltInParameter.RBS_OFFSET_PARAM).Set(-(AssistFunc.mmToFeet(this.channelDeep) / 2.0));
				result = cableTray;
			}
			catch (Exception)
			{
				result = null;
			}
			return result;
		}

		private void GetSharedParameter(CableTray ct)
		{
			Dictionary<string, ParameterType> dictionary = new Dictionary<string, ParameterType>();
            dictionary.Add("类别", (ParameterType)1);
			if (ct.GetParameter("类别") == null)
			{
				YArchitech.Revit.Electric.Common.SharedParameter.InsertSharedParameter(this.doc, BuiltInCategory.OST_CableTray, "电气数据", dictionary, true);
			}
		}

		private CableTrayType GetCableTrayType()
		{
			IList<Element> list = new FilteredElementCollector(this.doc).OfClass(typeof(CableTrayType)).ToElements();
			foreach (Element element in list)
			{
				CableTrayType cableTrayType = (CableTrayType)element;
				if (cableTrayType.Name.Equals("单轨电缆桥架"))
				{
					return cableTrayType;
				}
			}
			return list[0] as CableTrayType;
		}

		private bool RemoveDuplicates(List<XYZ> allPoint, XYZ point)
		{
			foreach (XYZ xyz in allPoint)
			{
				if (Math.Abs(xyz.X - point.X) <= this.js && Math.Abs(xyz.Y - point.Y) <= this.js)
				{
					return true;
				}
			}
			return false;
		}

		public XYZ IntersectionPoint(Curve curve1, Curve curve2)
		{
			IntersectionResultArray intersectionResultArray;
            if (curve1.Intersect(curve2, out intersectionResultArray) != SetComparisonResult.Overlap)
			{
				return null;
			}
			if (intersectionResultArray == null || intersectionResultArray.Size != 1)
			{
				return null;
			}
            return intersectionResultArray.get_Item(0).XYZPoint;
		}

        private Autodesk.Revit.ApplicationServices.Application app;

		private Document doc;

        private Autodesk.Revit.DB.View v;

		private Selection sel;

		private Level level;

		private double js = 0.01;

		private double channelDeep;

		private double channelWidth;
	}
}
